﻿using HandyControl.Tools;
using HandyControl.Tools.Extension;
using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shell;


namespace LpbPrj.Client.Controls
{
    [TemplatePart(Name = ElementNonClientArea, Type = typeof(UIElement))]
    public class CustomWindow : System.Windows.Window
    {
        #region fields

        private const string ElementNonClientArea = "PART_NonClientArea";

        private bool _isFullScreen;

        private Thickness _actualBorderThickness;

        private bool _showNonClientArea = true;

        private double _tempNonClientAreaHeight;

        private WindowState _tempWindowState;

        private WindowStyle _tempWindowStyle;

        private ResizeMode _tempResizeMode;

        private UIElement _nonClientArea;

        #endregion

        #region ctor

        static CustomWindow()
        {
            StyleProperty.OverrideMetadata(typeof(CustomWindow), new FrameworkPropertyMetadata(ResourceHelper.GetResource<Style>("CustomWindowWin10")));
        }

        public CustomWindow()
        {
            var chrome = new WindowChrome
            {
                CornerRadius = new CornerRadius(),
                GlassFrameThickness = new Thickness(0, 0, 0, 1),
                UseAeroCaptionButtons = false
            };

            BindingOperations.SetBinding(chrome, WindowChrome.CaptionHeightProperty, new System.Windows.Data.Binding(NonClientAreaHeightProperty.Name) { Source = this });
            WindowChrome.SetWindowChrome(this, chrome);
            //_commonPadding = Padding;

            Loaded += (s, e) => OnLoaded(e);
        }

        #endregion 

        #region prop

        public static readonly DependencyProperty NonClientAreaContentProperty = DependencyProperty.Register("NonClientAreaContent", typeof(object), typeof(CustomWindow), new PropertyMetadata(default(object)));
        public object NonClientAreaContent { get => GetValue(NonClientAreaContentProperty); set => SetValue(NonClientAreaContentProperty, value); }


        public static readonly DependencyProperty CloseButtonHoverBackgroundProperty = DependencyProperty.Register("CloseButtonHoverBackground", typeof(Brush), typeof(CustomWindow), new PropertyMetadata(default(Brush)));
        public Brush CloseButtonHoverBackground { get => (Brush)GetValue(CloseButtonHoverBackgroundProperty); set => SetValue(CloseButtonHoverBackgroundProperty, value); }


        public static readonly DependencyProperty CloseButtonHoverForegroundProperty = DependencyProperty.Register("CloseButtonHoverForeground", typeof(Brush), typeof(CustomWindow), new PropertyMetadata(default(Brush)));
        public Brush CloseButtonHoverForeground { get => (Brush)GetValue(CloseButtonHoverForegroundProperty); set => SetValue(CloseButtonHoverForegroundProperty, value); }


        public static readonly DependencyProperty CloseButtonBackgroundProperty = DependencyProperty.Register("CloseButtonBackground", typeof(Brush), typeof(CustomWindow), new PropertyMetadata(Brushes.Transparent));
        public Brush CloseButtonBackground { get => (Brush)GetValue(CloseButtonBackgroundProperty); set => SetValue(CloseButtonBackgroundProperty, value); }


        public static readonly DependencyProperty CloseButtonForegroundProperty = DependencyProperty.Register("CloseButtonForeground", typeof(Brush), typeof(CustomWindow), new PropertyMetadata(Brushes.White));
        public Brush CloseButtonForeground { get => (Brush)GetValue(CloseButtonForegroundProperty); set => SetValue(CloseButtonForegroundProperty, value); }


        public static readonly DependencyProperty OtherButtonBackgroundProperty = DependencyProperty.Register("OtherButtonBackground", typeof(Brush), typeof(CustomWindow), new PropertyMetadata(Brushes.Transparent));
        public Brush OtherButtonBackground { get => (Brush)GetValue(OtherButtonBackgroundProperty); set => SetValue(OtherButtonBackgroundProperty, value); }


        public static readonly DependencyProperty OtherButtonForegroundProperty = DependencyProperty.Register("OtherButtonForeground", typeof(Brush), typeof(CustomWindow), new PropertyMetadata(Brushes.White));
        public Brush OtherButtonForeground { get => (Brush)GetValue(OtherButtonForegroundProperty); set => SetValue(OtherButtonForegroundProperty, value); }


        public static readonly DependencyProperty OtherButtonHoverBackgroundProperty = DependencyProperty.Register("OtherButtonHoverBackground", typeof(Brush), typeof(CustomWindow), new PropertyMetadata(default(Brush)));
        public Brush OtherButtonHoverBackground { get => (Brush)GetValue(OtherButtonHoverBackgroundProperty); set => SetValue(OtherButtonHoverBackgroundProperty, value); }


        public static readonly DependencyProperty OtherButtonHoverForegroundProperty = DependencyProperty.Register("OtherButtonHoverForeground", typeof(Brush), typeof(CustomWindow), new PropertyMetadata(default(Brush)));
        public Brush OtherButtonHoverForeground { get => (Brush)GetValue(OtherButtonHoverForegroundProperty); set => SetValue(OtherButtonHoverForegroundProperty, value); }


        public static readonly DependencyProperty NonClientAreaBackgroundProperty = DependencyProperty.Register("NonClientAreaBackground", typeof(Brush), typeof(CustomWindow), new PropertyMetadata(default(Brush)));
        public Brush NonClientAreaBackground { get => (Brush)GetValue(NonClientAreaBackgroundProperty); set => SetValue(NonClientAreaBackgroundProperty, value); }


        public static readonly DependencyProperty NonClientAreaForegroundProperty = DependencyProperty.Register("NonClientAreaForeground", typeof(Brush), typeof(CustomWindow), new PropertyMetadata(default(Brush)));
        public Brush NonClientAreaForeground { get => (Brush)GetValue(NonClientAreaForegroundProperty); set => SetValue(NonClientAreaForegroundProperty, value); }


        public static readonly DependencyProperty NonClientAreaHeightProperty = DependencyProperty.Register("NonClientAreaHeight", typeof(double), typeof(CustomWindow), new PropertyMetadata(22.0));
        public double NonClientAreaHeight { get => (double)GetValue(NonClientAreaHeightProperty); set => SetValue(NonClientAreaHeightProperty, value); }


        public static readonly DependencyProperty ShowNonClientAreaProperty = DependencyProperty.Register("ShowNonClientArea", typeof(bool), typeof(CustomWindow), new PropertyMetadata(true, OnShowNonClientAreaChanged));
        public bool ShowNonClientArea { get => (bool)GetValue(ShowNonClientAreaProperty); set => SetValue(ShowNonClientAreaProperty, value); }


        public static readonly DependencyProperty ShowTitleProperty = DependencyProperty.Register("ShowTitle", typeof(bool), typeof(CustomWindow), new PropertyMetadata(true));
        public bool ShowTitle { get => (bool)GetValue(ShowTitleProperty); set => SetValue(ShowTitleProperty, value); }


        public static readonly DependencyProperty IsFullScreenProperty = DependencyProperty.Register("IsFullScreen", typeof(bool), typeof(CustomWindow), new PropertyMetadata(true, OnIsFullScreenChanged));
        public bool IsFullScreen { get => (bool)GetValue(IsFullScreenProperty); set => SetValue(IsFullScreenProperty, value); }


        public static readonly DependencyProperty ShowIconProperty = DependencyProperty.Register("ShowIcon", typeof(bool), typeof(CustomWindow), new PropertyMetadata(true));
        public bool ShowIcon { get => (bool)GetValue(ShowIconProperty); set => SetValue(ShowIconProperty, value); }

        #endregion

        #region methods

        #region public

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _nonClientArea = GetTemplateChild(ElementNonClientArea) as UIElement;
        }

        #endregion

        #region protected

        protected override void OnStateChanged(EventArgs e)
        {
            base.OnStateChanged(e);
            if (WindowState == WindowState.Maximized)
            {
                BorderThickness = new Thickness();
                _tempNonClientAreaHeight = NonClientAreaHeight;
            }
            else
            {
                BorderThickness = _actualBorderThickness;
                NonClientAreaHeight = _tempNonClientAreaHeight;
            }
        }

        protected void OnLoaded(RoutedEventArgs args)
        {
            _actualBorderThickness = BorderThickness;
            _tempNonClientAreaHeight = NonClientAreaHeight;

            if (WindowState == WindowState.Maximized)
            {
                BorderThickness = new Thickness();
            }

            CommandBindings.Add(new CommandBinding(SystemCommands.MinimizeWindowCommand, (s, e) => WindowState = WindowState.Minimized));
            CommandBindings.Add(new CommandBinding(SystemCommands.MaximizeWindowCommand, (s, e) => WindowState = WindowState.Maximized));
            CommandBindings.Add(new CommandBinding(SystemCommands.RestoreWindowCommand, (s, e) => WindowState = WindowState.Normal));
            CommandBindings.Add(new CommandBinding(SystemCommands.CloseWindowCommand, (s, e) => Close()));
            CommandBindings.Add(new CommandBinding(SystemCommands.ShowSystemMenuCommand, ShowSystemMenu));

            _tempWindowState = WindowState;
            _tempWindowStyle = WindowStyle;
            _tempResizeMode = ResizeMode;

            SwitchIsFullScreen(_isFullScreen);
            SwitchShowNonClientArea(_showNonClientArea);

            if (SizeToContent != SizeToContent.WidthAndHeight)
                return;

            SizeToContent = SizeToContent.Height;
            Dispatcher.BeginInvoke(new Action(() => { SizeToContent = SizeToContent.WidthAndHeight; }));
        }

        protected override void OnContentRendered(EventArgs e)
        {
            base.OnContentRendered(e);
            if (SizeToContent == SizeToContent.WidthAndHeight)
                InvalidateMeasure();
        }

        #endregion

        #region private

        private static void OnShowNonClientAreaChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctl = (CustomWindow)d;
            ctl.SwitchShowNonClientArea((bool)e.NewValue);
        }

        private void SwitchShowNonClientArea(bool showNonClientArea)
        {
            if (_nonClientArea == null)
            {
                _showNonClientArea = showNonClientArea;
                return;
            }

            if (showNonClientArea)
            {
                if (IsFullScreen)
                {
                    _nonClientArea.Show(false);
                    _tempNonClientAreaHeight = NonClientAreaHeight;
                    NonClientAreaHeight = 0;
                }
                else
                {
                    _nonClientArea.Show(true);
                    NonClientAreaHeight = _tempNonClientAreaHeight;
                }
            }
            else
            {
                _nonClientArea.Show(false);
                _tempNonClientAreaHeight = NonClientAreaHeight;
                NonClientAreaHeight = 0;
            }
        }

        private static void OnIsFullScreenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctl = (CustomWindow)d;
            ctl.SwitchIsFullScreen((bool)e.NewValue);
        }

        private void SwitchIsFullScreen(bool isFullScreen)
        {
            if (_nonClientArea == null)
            {
                _isFullScreen = isFullScreen;
                return;
            }

            if (isFullScreen)
            {
                _nonClientArea.Show(false);
                _tempNonClientAreaHeight = NonClientAreaHeight;
                NonClientAreaHeight = 0;

                _tempWindowState = WindowState;
                _tempWindowStyle = WindowStyle;
                _tempResizeMode = ResizeMode;
                WindowStyle = WindowStyle.None;
                ////下面三行不能改变，就是故意的
                //WindowState = WindowState.Maximized;
                //WindowState = WindowState.Minimized;
                WindowState = WindowState.Maximized;
            }
            else
            {
                if (ShowNonClientArea)
                {
                    _nonClientArea.Show(true);
                    NonClientAreaHeight = _tempNonClientAreaHeight;
                }
                else
                {
                    _nonClientArea.Show(false);
                    _tempNonClientAreaHeight = NonClientAreaHeight;
                    NonClientAreaHeight = 0;
                }

                WindowState = _tempWindowState;
                WindowStyle = _tempWindowStyle;
                ResizeMode = _tempResizeMode;
            }
        }

        private void ShowSystemMenu(object sender, ExecutedRoutedEventArgs e)
        {
            var point = WindowState == WindowState.Maximized
                ? new Point(0, NonClientAreaHeight)
                : new Point(Left, Top + NonClientAreaHeight);
            SystemCommands.ShowSystemMenu(this, point);
        }

        #endregion

        #endregion
    }
}
